<?php

/**
 * 请求处理类
 * User: wz_zh
 * Date: 2017/7/5
 * Time: 16:23
 */

namespace PKFrame\Lib;
defined('PATH_PK') or die();

use PKFrame\DataHandler\Arrays;
use PKFrame\DataHandler\Auth;
use PKFrame\DataHandler\Str;

class Request
{
    private static $instance;
    /**
     * @var string 域名（含协议和端口）
     */
    private static $domain;

    /**
     * @var string URL地址
     */
    private static $url;

    /**
     * @var string 基础URL
     */
    private static $baseUrl;

    /**
     * @var string 当前执行的文件
     */
    private static $baseFile;

    /**
     * @var string 访问的ROOT地址
     */
    private static $root;

    /**
     * @var string pathInfo
     */
    private static $pathInfo;

    /**
     * @var string pathInfo（不含后缀）
     */
    //    private static $path;

    /**
     * @var array 当前路由信息
     */
    private static $routeInfo = [];

    /**
     * @var array 当前调度信息
     */
    private static $dispatch = [];
    private static $module;
    private static $controller;
    private static $action;
    // 当前语言集
    private static $langSet;

    /**
     * @var array 请求参数
     */
    private static $param = [];
    private static $get = [];
    private static $post = [];
    private static $input = '';
    private static $request = [];
    private static $route = [];
    private static $put;
    private static $file = [];
    private static $server = [];
    private static $header = [];
    private static $env = [];

    /**
     * @var array 资源类型
     */
    private static $mimeType = array(
        'xml' => 'application/xml,text/xml,application/x-xml',
        'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
        'js' => 'text/javascript,application/javascript,application/x-javascript',
        'css' => 'text/css',
        'rss' => 'application/rss+xml',
        'yaml' => 'application/x-yaml,text/yaml',
        'atom' => 'application/atom+xml',
        'pdf' => 'application/pdf',
        'text' => 'text/plain',
        'image' => 'image/png,image/jpg,image/jpeg,image/pjpeg,image/gif,image/webp,image/*',
        'csv' => 'text/csv',
        'html' => 'text/html,application/xhtml+xml,*/*',
    );

    public static function instance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static;
        }

        return static::$instance;
    }

    /**
     * 设置或获取当前包含协议的域名
     * @access public
     * @param string $domain 域名
     * @return string
     */
    public function domain($domain = null): string
    {
        if (!is_null($domain)) {
            self::$domain = $domain;
        } elseif (empty(self::$domain)) {
            self::$domain = $this->scheme() . '://' . $this->host();
        }
        return self::$domain . '/';
    }

    /**
     * 获取 origin
     * @return string
     */
    public function origin()
    {
        return $this->header('origin');
    }

    /**
     * 设置或获取当前完整URL 包括QUERY_STRING
     * @access public
     * @param string|true $url URL地址 true 带域名获取
     * @return string
     */
    public function url($url = null): string
    {
        if (!is_null($url) && true !== $url) {
            self::$url = $url;
        } elseif (is_null(self::$url)) {
            if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
                self::$url = $_SERVER['HTTP_X_REWRITE_URL'];
            } elseif (isset($_SERVER['REQUEST_URI'])) {
                self::$url = $_SERVER['REQUEST_URI'];
            } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
                self::$url = $_SERVER['ORIG_PATH_INFO'] . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '');
            } else {
                self::$url = '';
            }
        }
        $urlArr = (explode('/index.php', self::$url));
        return true === $url ? $this->domain() . ltrim(self::$url, '/') : (count($urlArr) == 2 ? $urlArr[1] : '');
    }

    /**
     * 设置或获取当前URL 不含QUERY_STRING
     * @access public
     * @param string $url URL地址
     * @return string
     */
    public function baseUrl($url = null): string
    {
        if (!is_null($url) && true !== $url) {
            self::$baseUrl = $url;
        } elseif (!self::$baseUrl) {
            $str = $this->url();
            self::$baseUrl = strpos($str, '?') ? strstr($str, '?', true) : $str;
        }
        return true === $url ? $this->domain() . ltrim(self::$baseUrl, '/') : self::$baseUrl;
    }

    /**
     * 设置或获取当前执行的文件 SCRIPT_NAME
     * @access public
     * @param string $file 当前执行的文件
     * @return string
     */
    public function baseFile($file = null): string
    {
        if (!is_null($file) && true !== $file) {
            self::$baseFile = $file;
        } elseif (!self::$baseFile) {
            $url = '';
            $script_name = basename($_SERVER['SCRIPT_FILENAME']);
            if (basename($_SERVER['SCRIPT_NAME']) === $script_name) {
                $url = $_SERVER['SCRIPT_NAME'];
            } elseif (basename($_SERVER['PHP_SELF']) === $script_name) {
                $url = $_SERVER['PHP_SELF'];
            } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $script_name) {
                $url = $_SERVER['ORIG_SCRIPT_NAME'];
            } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $script_name)) !== false) {
                $url = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $script_name;
            } elseif (isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) === 0) {
                $url = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME']));
            }
            self::$baseFile = $url;
        }
        return true === $file ? $this->domain() . ltrim(self::$baseFile, '/') : self::$baseFile;
    }

    /**
     * 设置或获取URL访问根地址
     * @access public
     * @param string $url URL地址
     * @return string
     */
    public function root($url = null): string
    {
        if (!is_null($url) && true !== $url) {
            self::$root = $url;
        } elseif (!self::$root) {
            $file = $this->baseFile();
            if ($file && 0 !== strpos($this->url(), $file)) {
                $file = str_replace('\\', '/', dirname($file));
            }
            self::$root = rtrim($file, '/');
        }
        return true === $url ? $this->domain() . ltrim(self::$root, '/') : self::$root;
    }

    /**
     * 获取当前请求URL的pathinfo信息（含URL后缀）
     * @access public
     * @return string
     */
    public function pathInfo(): string
    {
        if (is_null(self::$pathInfo)) {
            // 分析PATHINFO信息
            if (isset($_SERVER['ORIG_PATH_INFO'])) {
                self::$pathInfo = ltrim($_SERVER['ORIG_PATH_INFO'], '/');
            } elseif (isset($_SERVER['PATH_INFO'])) {
                self::$pathInfo = ltrim($_SERVER['PATH_INFO'], '/');
            } else {
                self::$pathInfo = '/';
            }
        }
        return self::$pathInfo;
    }

    /**
     * 当前URL的访问后缀
     * @access public
     * @return string
     */
    public function ext(): string
    {
        return pathinfo($this->pathinfo(), PATHINFO_EXTENSION);
    }

    /**
     * 获取当前请求的时间
     * @access public
     * @param bool $float 是否使用浮点类型
     * @return integer|float
     */
    public function time($float = false)
    {
        return $float ? $this->server('REQUEST_TIME_FLOAT') : $this->server('REQUEST_TIME');
    }

    /**
     * 当前请求的资源类型
     * @access public
     * @return null|string
     */
    public function type(): ?string
    {
        $accept = $this->server('HTTP_ACCEPT');
        if (is_null($accept)) {
            return null;
        }
        foreach (self::$mimeType as $key => $val) {
            $array = explode(',', $val);
            if (array_search($accept, $array)) {
                return $key;
            }
        }
        return null;
    }

    /**
     * 设置资源类型
     * @access public
     * @param string|array $type 资源类型名
     * @param string $val 资源类型
     * @return void
     */
    public function mimeType($type, $val = '')
    {
        if (is_array($type)) {
            self::$mimeType = array_merge(self::$mimeType, $type);
        } else {
            self::$mimeType[$type] = $val;
        }
    }

    /**
     * 是否存在某个请求参数
     * @access public
     * @param string $name 变量名
     * @param string $type 变量类型
     * @return mixed
     */
    public function has(string $name, $type = 'param'): bool
    {
        if (version_compare(phpversion(), '7.0.0', '>=')) {
            $param = isset(self::${$type}) && !empty(self::${$type}) ? self::${$type} : [];
        } else {
            $param = isset(self::$$type) && !empty(self::$$type) ? self::$$type : [];
        }
        if (strtolower($type) != 'has' && !Arrays::Is($param) && method_exists($this, $type)) {
            $param = $this->{$type}();
        }
        $result = false;
        // 按.拆分成多维数组进行判断
        if (stristr($name, ',')) {
            $nameArr = explode(',', $name);
            foreach ($nameArr as $val) {
                $result = array_key_exists($val, $param);
                if (!$result) {
                    break;
                }
            }
        } else {
            $result = array_key_exists($name, $param);
        }
        return $result;
    }

    /**
     * 当前的请求类型
     * @access public
     * @return string
     */
    public function method(): string
    {
        return $this->server('REQUEST_METHOD');
    }

    /**
     * 是否为GET请求
     * @access public
     * @return bool
     */
    public function isGet(): bool
    {
        return $this->method() == 'GET';
    }

    /**
     * 是否为POST请求
     * @access public
     * @return bool
     */
    public function isPost(): bool
    {
        return $this->method() == 'POST';
    }

    /**
     * 是否为PUT请求
     * @access public
     * @return bool
     */
    public function isPut(): bool
    {
        return $this->method() == 'PUT';
    }

    /**
     * 是否为DELTE请求
     * @access public
     * @return bool
     */
    public function isDelete(): bool
    {
        return $this->method() == 'DELETE';
    }

    /**
     * 是否为HEAD请求
     * @access public
     * @return bool
     */
    public function isHead(): bool
    {
        return $this->method() == 'HEAD';
    }

    /**
     * 是否为PATCH请求
     * @access public
     * @return bool
     */
    public function isPatch(): bool
    {
        return $this->method() == 'PATCH';
    }

    /**
     * 是否为OPTIONS请求
     * @access public
     * @return bool
     */
    public function isOptions(): bool
    {
        return $this->method() == 'OPTIONS';
    }

    /**
     * 是否为cli
     * @access public
     * @return bool
     */
    public function isCli(): bool
    {
        return PHP_SAPI == 'cli';
    }

    /**
     * 是否为cgi
     * @access public
     * @return bool
     */
    public function isCgi(): bool
    {
        return strpos(PHP_SAPI, 'cgi') === 0;
    }

    /**
     * 获取当前请求的参数
     * @access public
     * @param string|array $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function param($name = '', $default = null)
    {
        if (!empty($name) && !is_null($default)) {
            self::$param[$name] = Auth::FilterValue($default);
        } elseif (!empty($name) && is_array($name)) {
            self::$param = array_merge(self::$param, $name);
        } elseif (!empty($name) && is_null($default)) {
            return array_key_exists($name, self::$param) ? self::$param[$name] : null;
        }
        return self::$param;
    }

    /**
     * 服务器指纹
     * @return string
     */
    public function ServerFingerprint(): string
    {
        return md5($this->server('OS') . '_*_' . $this->server('COMPUTERNAME')
            . '_@_' . PATH_ROOT);
    }

    /**
     * 设置获取路由参数
     * @access public
     * @param string|array $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function route($name = '', $default = null): array
    {
        $query_str = request()->server('REQUEST_URI');
        Auth::checkPHPCode($query_str);
        if (empty(self::$route)) {
            $index_pos = strpos($query_str, '/index.php/');
            if (is_numeric($index_pos) && $index_pos == 0) {
                $parts = preg_split('#\?#i', $this->url(), 2);
                $isAuth_router = (is_array($parts) && count($parts) >= 1)
                    && (!empty($parts[0]) && !stristr($parts[0], '.') && stristr($parts[0], '/'));
                $query_router = $parts[0];
            } else {
                $query_router = ltrim(explode('?', $query_str)[0], '/');
                $parts = explode('/', $query_router);
                $isAuth_router = (is_array($parts) && count($parts) >= 1)
                    && !stristr($query_str, '.') && stristr($query_str, '/');
            }
            if (!$isAuth_router) {
                if (file_exists(PATH_ROOT . 'index.htm')) {
                    header('HTTP/1.1 301 Moved Permanently');
                    header('location:/index.htm');
                } else {
                    die();
                }
            }
            $this->routeInfo(trim($query_router, "/"));
            $this->request(empty(self::$routeInfo) ? [] : self::$routeInfo);
            $this->action('main');
            if (count(self::$request) > 0) {
                !isset(self::$request[0]) ?: $this->module(self::$request[0]);
                !isset(self::$request[1]) ?: $this->controller(self::$request[1]);
                if (isset(self::$request[2])) {
                    $this->action(self::$request[2]);
                }
            }
        }
        if (is_array($name)) {
            return self::$route = array_merge(self::$route, $name);
        }
        if (!empty($name) && !is_null($default)) {
            self::$route[$name] = Auth::FilterValue($default);
        } elseif (!empty($name) && is_null($default)) {
            return self::$route[$name];
        }
        return self::$route;
    }

    /**
     * 循环检查
     * @param $array
     * @param bool $blank 是否去空格
     * @param bool $ishtml
     * @return array
     */
    public function fileter($array = [], $blank = FALSE, $ishtml = FALSE): array
    {
        $result = [];
        if (is_array($array) == FALSE) {
            return $result;
        }
        foreach ($array as $key => $value) {
            if (Arrays::Is($value)) {
                $result[Auth::FilterValue($key)] = $this->fileter($value);
            } else {
                $value = $blank ? trim($value) : $value;
                $result[Auth::FilterValue($key, $ishtml)] = Auth::FilterValue($value, $ishtml);
            }
        }
        return $result;
    }

    /**
     * 设置获取GET参数
     * @access public
     * @param string|array $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function get($name = '', $default = null)
    {
        if (empty(self::$get)) {
            $get = $_GET;
            if (!Arrays::Is($get)) {
                $arr = explode('?', $_SERVER['REQUEST_URI']);
                !isset($arr[1]) ?: $get = Str::ToArray($arr[1]);
            }
            if (Arrays::Is($get)) {
                foreach ($get as $key => $value) {
                    self::$get[$key] = Auth::UrlReplace($value);
                }
            }
        }
        if (is_array($name)) {
            return self::$get = array_merge(self::$get, $name);
        }
        if (!empty($name) && !is_null($default)) {
            self::$get[$name] = Auth::FilterValue($default);
        } elseif (!empty($name) && is_null($default)) {
            return isset(self::$get[$name]) ? self::$get[$name] : '';
        }
        return self::$get;
    }

    /**
     * 设置获取POST参数
     * @access public
     * @param string $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function post($name = '', $default = null)
    {
        if (empty(self::$post)) {
            $this->input();
            $post = $_POST;
            if (empty($_POST) && (false !== strpos($this->contentType(), 'application/json')
                    || false !== strpos($this->contentType(), 'text/plain'))) {
                try {
                    $post = json_decode(self::$input, FILTER_VALIDATE_BOOLEAN);
                } catch (\Exception $exception) {
                    out()->notice($exception->getMessage());
                }
            } else {
                foreach ($_POST as $key => $item) {
                    Auth::checkPHPCode($key);
                    Auth::checkPHPCode($item);
                }
            }
            if (Arrays::Is($post)) {
                foreach ($post as $key => $value) {
                    self::$post[$key] = Auth::Htmlspecialchars($value, ENT_QUOTES);
                }
            }
        }
        if (is_array($name)) {
            return self::$post = array_merge(self::$post, $name);
        }
        if (!empty($name) && !is_null($default)) {
            self::$post[$name] = Auth::FilterValue($default);
        } elseif (!empty($name) && isset(self::$post[$name]) && is_null($default)) {
            return self::$post[$name];
        } elseif (!empty($name) && is_array(self::$post) && !array_key_exists($name, self::$post)) {
            return '';
        }
        return self::$post;
    }

    /**
     * 保存 php://input
     */
    public function input()
    {
        self::$input = file_get_contents('php://input');
        Auth::checkPHPCode(self::$input);
        return self::$input;
    }

    /**
     * 设置获取PUT参数
     * @access public
     * @param string|array $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function put($name = '', $default = null)
    {
        $this->input();
        if (is_null(self::$put)) {
            if (empty($_POST) && (false !== strpos($this->contentType(), 'application/json')
                    || false !== strpos($this->contentType(), 'text/plain'))) {
                self::$put = json_decode(self::$input, true);
            } else {
                parse_str(self::$input, self::$put);
            }
        }
        if (is_array($name)) {
            self::$put = is_null(self::$put) ? $name : array_merge(self::$put, $name);
        } elseif (is_string($name) && !is_null($default)) {
            self::$put[$name] = Auth::FilterValue($default);
        }
        return self::$put;
    }

    /**
     * 设置获取DELETE参数
     * @access public
     * @param string|array $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function delete($name = '', $default = null)
    {
        return $this->put($name, $default);
    }

    /**
     * 设置获取PATCH参数
     * @access public
     * @param string|array $name 变量名
     * @param mixed $default 默认值
     * @return mixed
     */
    public function patch($name = '', $default = null)
    {
        return $this->put($name, $default);
    }

    /**
     * 获取request变量
     * @param string $name 数据名称
     * @param string $default 默认值
     * @return mixed
     */
    public function request($name = '', $default = null)
    {
        if (empty(self::$request)) {
            self::$request = $_REQUEST;
        }
        if (is_array($name)) {
            return self::$request = array_merge(self::$request, $name);
        } elseif (is_string($name) && !is_null($default)) {
            self::$request[$name] = $default;
        }
        return isset(self::$request[$name]) ? self::$request[$name] : self::$request;
    }

    /**
     * 获取或设置 session 数据
     * @param string $name 数据名称
     * @param string $default 默认值
     * @param bool $is_del 是否删除
     * @return array|mixed|string|null
     */
    public function session($name = '', $default = null, $is_del = false)
    {
        $session = null;
        ob_start();
        switch (session_status()) {
            case PHP_SESSION_DISABLED:
                // 会话是被禁用的
                out()->notice('The session is disabled.');
                break;
            case PHP_SESSION_NONE:
                // 会话是启用的，但不存在当前会话。
                session_start();
                break;
            case PHP_SESSION_ACTIVE:
                // 会话是启用的，而且存在当前会话。
                break;
        }
        if (is_null($default) && $is_del == true && isset($_SESSION[$name])) {
            unset($_SESSION[$name]);
        } elseif (is_null($default) && $is_del == false && isset($_SESSION[$name])) {
            $session = Arrays::Unserialize($_SESSION[$name]);
            !empty($session) ?: $session = $_SESSION[$name];
        } elseif (!is_null($default) && $is_del == false) {
            $_SESSION[$name] = $session = is_array($default) ? serialize($default) : $default;
        } elseif (empty($name)) {
            $session = session_id();
        }
        ob_end_clean();
        return $session;
    }

    /**
     * 获取cookie参数
     * @param string|array $name 变量名
     * @param null $default 数据
     * @param int $expire 有效期
     * @param bool $is_auth_code 是否安全码处理
     * @return null
     */
    public function cookie($name = '', $default = null, $expire = 0, $is_auth_code = true)
    {
        $domainArr = explode(':', $this->host());
        $key = PATH_PK . 'cookies' . $name;
        if (is_null($default) && isset($_COOKIE[$name])) {
            // 获取指定的 cookies key
            $default = $_COOKIE[$name];
            return !$is_auth_code ? $default : Auth::Base64Encode($default, false, $key);
        } elseif (empty($default) && isset($_COOKIE[$name])) {
            // 清空指定的 cookies key
            return setcookie($name, '', SYS_TIME - 3600, '/', $domainArr[0]);
        }
        if (!is_null($default)) {
            // 设置指定 cookies key 的 value
            !$is_auth_code ?: $default = Auth::Base64Encode($default, true, $key);
            setcookie($name, $default, SYS_TIME + ($expire), '/', $domainArr[0]);
            return $_COOKIE[$name];
        }
        return null;
    }

    /**
     * 获取server参数
     * @access public
     * @param string|array $name 数据名称
     * @param string $default 默认值
     * @return array|mixed|string
     */
    public function server($name = '', $default = null)
    {
        !empty(self::$server) ?: self::$server = $_SERVER;
        if (is_array($name)) {
            self::$server = array_merge(self::$server, $name);
        } elseif (!empty($name) && !empty($default)) {
            self::$server[$name] = $default;
        }
        if (!empty($name)) {
            if (array_key_exists($name, self::$server)) {
                return self::$server[$name];
            } else {
                $name = strtoupper($name);
                if (array_key_exists($name, self::$server)) {
                    return self::$server[$name];
                } else {
                    return '';
                }
            }
        } else {
            return self::$server;
        }
    }

    public function ServerByOS(): string
    {
        if ($os = $this->server('OS')) {
            return strtolower($os);
        } else {
            return strtolower(php_uname());
        }
    }

    /**
     * 获取上传的文件信息
     * @param string $name 名称
     * @return array|mixed
     */
    public function file($name = ''): array
    {
        if (empty(self::$file) && isset($_FILES[$name])) {
            self::$file = $_FILES[$name];
        }
        return self::$file;
    }

    /**
     * 获取环境变量
     * @param string|array $name 数据名称
     * @return mixed
     */
    public function env($name = '')
    {
        if (empty(self::$env)) {
            self::$env = $_ENV;
        }
        return self::$env[strtoupper($name)];
    }

    /**
     * 设置或者获取当前的Header
     * @access public
     * @param string|array $name header名称
     * @param string $default 默认值
     * @return string|null
     */
    public function header($name = '', $default = null): ?string
    {
        if (empty(self::$header)) {
            $header = [];
            if (function_exists('apache_request_headers') && $result = apache_request_headers()) {
                $header = $result;
            } else {
                $server = self::$server ?: $_SERVER;
                foreach ($server as $key => $val) {
                    if (0 === strpos($key, 'HTTP_')) {
                        $key = str_replace('_', '-', strtolower(substr($key, 5)));
                        $header[$key] = $val;
                    }
                }
                if (isset($server['CONTENT_TYPE'])) {
                    $header['content-type'] = $server['CONTENT_TYPE'];
                }
                if (isset($server['CONTENT_LENGTH'])) {
                    $header['content-length'] = $server['CONTENT_LENGTH'];
                }
            }
            self::$header = array_change_key_case($header);
        }
        if (is_array($name)) {
            self::$header = array_merge(self::$header, $name);
        }
        if ('' === $name) {
            return '';
        }
        $name = str_replace('_', '-', strtolower($name));
        return isset(self::$header[$name]) ? self::$header[$name] : $default;
    }

    /**
     * 当前是否ssl
     * @access public
     * @return bool
     */
    public function isSsl(): bool
    {
        $server_https = $this->server('HTTPS');
        $server_RS = $this->server('REQUEST_SCHEME');
        $server_SR = $this->server('SERVER_PORT');
        $server_HXFP = $this->server('HTTP_X_FORWARDED_PROTO');
        if ('1' == $server_https || 'on' == strtolower($server_https)) {
            return true;
        } elseif ('https' == $server_RS) {
            return true;
        } elseif ('443' == $server_SR) {
            return true;
        } elseif ('https' == $server_HXFP) {
            return true;
        }
        return false;
    }

    /**
     * 当前是否Ajax请求
     * @access public
     * @return bool
     */
    public function isAjax(): bool
    {
        return request()->contentType() == 'application/json' ||
            strtolower('XMLHttpRequest') == strtolower($this->server('HTTP_X_REQUESTED_WITH'));
    }

    /**
     * 当前是否Pjax请求
     * @access public
     * @return bool
     */
    public function isPjax(): bool
    {
        return $this->server('HTTP_X_PJAX') ? true : false;
    }

    /**
     * 返回地址
     * @return null
     */
    function referer()
    {
        return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
    }

    /**
     * 获取服务端IP地址
     * @return mixed
     */
    public function ServerIP(): string
    {
        return $this->server('SERVER_ADDR');
    }

    /**
     * 获取服务端IP地址
     * @return string
     */
    public function GuestIP(): string
    {
        if (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
            $ip_address = getenv('HTTP_X_FORWARDED_FOR');
        } elseif (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
            $ip_address = getenv('HTTP_CLIENT_IP');
        } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
            $ip_address = getenv('REMOTE_ADDR');
        } elseif (($server_ADDR = $this->server('REMOTE_ADDR')) && strcasecmp($server_ADDR, 'unknown')) {
            $ip_address = $server_ADDR;
        }
        if (isset($ip_address)) {
            return preg_match('/[\d\.]{7,15}/', $ip_address, $matches) ? $matches[0] : '127.0.0.1';
        } else {
            return '';
        }
    }

    /**
     * 检测是否为内部IP
     * @param $ip
     * @return mixed
     */
    public function isInsideIp($ip)
    {
        return in_array(strtok($ip, '.'), array('10', '127', '168', '192'));
    }

    /**
     * 检测是否使用手机访问
     * @access public
     * @return bool
     */
    public function isMobile(): bool
    {
        if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) {
            return true;
        } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) {
            return true;
        } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) {
            return true;
        } elseif (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $_SERVER['HTTP_USER_AGENT'])) {
            return true;
        } elseif (\request()->get('m')) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取浏览器的内核名和版本号
     * @param string $is_browser_name 判断是否为指定的浏览器内核名
     * @return bool|string
     */
    public function browserAndVer($is_browser_name = '')
    {
        $agent = $this->server('HTTP_USER_AGENT');
        if (empty($agent)) {
            return '';
        }
        $browser = 'unknown';
        $browser_ver = '';
        // 包括 ie11 判断
        if (preg_match('/MSIE\s(\d+)\..*/i', $agent, $regs)) {
            $browser = "ie";
            $browser_ver = $regs[1];
        } elseif (preg_match('/FireFox\/(\d+)\..*/i', $agent, $regs)) {
            $browser = "firefox";
            $browser_ver = $regs[1];
        } elseif (preg_match('/Opera[\s|\/](\d+)\..*/i', $agent, $regs)) {
            $browser = 'opera';
            $browser_ver = $regs[1];
        } elseif (preg_match('/Chrome\/(\d+)\..*/i', $agent, $regs)) {
            $browser = "chrome";
            $browser_ver = $regs[1];
        } elseif ((strpos($agent, 'Chrome') == false) && preg_match('/Safari\/(\d+)\..*$/i', $agent, $regs)) {
            $browser = 'safari';
            $browser_ver = $regs[1];
        }
        if (!empty($is_browser_name)) {
            return Auth::Addslashes($browser) == $is_browser_name;
        }
        return Auth::Addslashes($browser . ' ' . $browser_ver);
    }

    /**
     * 当前URL地址中的scheme参数
     * @access public
     * @return string
     */
    public function scheme(): string
    {
        return $this->isSsl() ? 'https' : 'http';
    }

    /**
     * 当前请求URL地址中的query参数
     * @access public
     * @return string
     */
    public function Exec(): string
    {
        return $this->server('QUERY_STRING');
    }

    /**
     * 当前请求的host
     * @access public
     * @return string
     */
    public function host(): string
    {
        return $this->server('HTTP_HOST');
    }

    /**
     * 当前请求URL地址中的port参数
     * @access public
     * @return integer
     */
    public function port()
    {
        return $this->server('SERVER_PORT');
    }

    /**
     * 当前请求 SERVER_PROTOCOL
     * @access public
     * @return integer
     */
    public function protocol()
    {
        return $this->server('SERVER_PROTOCOL');
    }

    /**
     * 当前请求 REMOTE_PORT
     * @access public
     * @return integer
     */
    public function remotePort()
    {
        return $this->server('REMOTE_PORT');
    }

    /**
     * 当前请求 HTTP_CONTENT_TYPE
     * @access public
     * @return string
     */
    public function contentType(): string
    {
        $contentType = $this->server('CONTENT_TYPE');
        if ($contentType) {
            if (strpos($contentType, ';')) {
                list($type) = explode(';', $contentType);
            } else {
                $type = $contentType;
            }
            return trim($type);
        }
        return '';
    }

    /**
     * 获取当前请求的路由信息
     * @access public
     * @param string $route 路由名称
     * @return array
     */
    public function routeInfo($route = ''): array
    {
        if (!empty($route)) {
            $is_install = isInstall();
            // 需要重置环境，但又不是导入数据的转移请求
            if ($is_install && !stristr($route, 'DataBase')) {
                if ($route == 'Install/Inquiry') {
                    fileHelper()->PutContents(PATH_CACHE, SYSTEM_LOCK, request()->ServerFingerprint());
                    exit();
                } elseif (!stristr($route, 'Install')) {
                    $route = 'Install/Inquiry';
                }
            }
            self::$routeInfo = explode("/", $route);
        }
        return self::$routeInfo;
    }

    /**
     * 设置或者获取当前请求的调度信息
     * @access public
     * @param array $dispatch 调度信息
     * @return array
     */
    public function dispatch($dispatch = null): array
    {
        if (!is_null($dispatch)) {
            self::$dispatch = $dispatch;
        }
        return self::$dispatch;
    }

    /**
     * 设置或者获取当前的模块名
     * @access public
     * @param string $module 模块名
     * @return string|Request
     */
    public function module($module = null)
    {
        if (!is_null($module)) {
            self::$module = ucfirst($module);
        }
        return self::$module;
    }

    /**
     * 设置或者获取当前的控制器名
     * @access public
     * @param string $controller 控制器名
     * @return string|Request
     */
    public function controller($controller = null)
    {
        if (!is_null($controller)) {
            self::$controller = ucfirst($controller);
        }
        return self::$controller;
    }

    /**
     * 设置或者获取当前的操作名
     * @access public
     * @param string $action 操作名
     * @return string|Request
     */
    public function action($action = null)
    {
        if (!is_null($action)) {
            self::$action = ucfirst($action);
        }
        return self::$action;
    }

    /**
     * 设置或者获取当前的语言
     * @access public
     * @param string $lang 语言名
     * @return string
     */
    public function language(string $lang = ''): string
    {
        if (!empty($lang)) {
            self::$langSet = $lang;
        }
        return self::$langSet ?: '';
    }
}
